using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Ccr.Core;
using Microsoft.Dss.Core;
using Microsoft.Dss.Core.Attributes;
using Microsoft.Dss.ServiceModel.Dssp;
using Microsoft.Dss.ServiceModel.DsspServiceBase;
using W3C.Soap;

using ds = Microsoft.Dss.Services.Directory;
using dssp = Microsoft.Dss.ServiceModel.Dssp;
using diffdrive = Microsoft.Robotics.Services.Drive.Proxy;

namespace UrbanDrive
{
    [DisplayName("Urban Drive")]
    [Description("Urban Drive")]    
    [Contract(Contract.Identifier)]
    class UrbanDriveService : DsspServiceBase
    {
        [ServiceState]
        UrbanDriveState _state = new UrbanDriveState();

        [ServicePort("/UrbanDrive", AllowMultipleInstances = true)]
        UrbanDriveOperations _mainPort = new UrbanDriveOperations();

        public UrbanDriveService(DsspServiceCreationPort creationPort)
            : base(creationPort)
        {
        }

        protected override void Start()
        {
            Activate(Arbiter.Interleave(
                new TeardownReceiverGroup(),
                new ExclusiveReceiverGroup
                (
                    Arbiter.ReceiveWithIterator<Connect>(true, _mainPort, ConnectHandler),
                    Arbiter.ReceiveWithIterator<AllStop>(true, _mainPort, AllStopHandler),
                    Arbiter.ReceiveWithIterator<SetDrivePower>(true, _mainPort, SetPowerHandler)
                ),
                new ConcurrentReceiverGroup
                (
                    Arbiter.Receive<DsspDefaultLookup>(true, _mainPort, DefaultLookupHandler)
                )
            ));

            DirectoryInsert();
        }


        diffdrive.DriveOperations _drivePort = null;

        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public virtual IEnumerator<ITask> ConnectHandler(Connect update)
        {
            UriBuilder builder = new UriBuilder(Schemes.DsspTcp, "localhost", 0, ServicePaths.InstanceDirectory);
            builder.Scheme = new Uri(ServiceInfo.Service).Scheme;

            ds.DirectoryPort port = ServiceForwarder<ds.DirectoryPort>(builder.Uri);
            ds.Get get = new ds.Get();

            port.Post(get);
            ServiceInfoType[] list = null;

            yield return Arbiter.Choice(get.ResponsePort,
                delegate(ds.GetResponseType response)
                {
                    list = response.RecordList;
                },
                delegate(Fault fault)
                {
                    list = new ServiceInfoType[0];
                    LogError(fault);
                }
            );

            foreach (ServiceInfoType info in list)
            {
                if (info.Contract == diffdrive.Contract.Identifier)
                {
                    LogInfo("### Drive service founded");

                    _drivePort = ServiceForwarder<diffdrive.DriveOperations>(info.Service);                    
                }
            }

            update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }


        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public IEnumerator<ITask> SetPowerHandler(SetDrivePower setPower)
        {
            _drivePort.SetDrivePower(setPower.Body);

            setPower.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }


        [ServiceHandler(ServiceHandlerBehavior.Exclusive)]
        public IEnumerator<ITask> AllStopHandler(AllStop estop)
        {
            _drivePort.AllStop(estop.Body);

            estop.ResponsePort.Post(DefaultUpdateResponseType.Instance);
            yield break;
        }        

    }
}
